package zju.ccnt.rest.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import zju.ccnt.fileserverProxy.service.FileServerLoadBalance;
import zju.ccnt.fileserverProxy.service.FileServerProxy;
import zju.ccnt.rest.api.*;
import zju.ccnt.rest.domain.BusinessResource;
import zju.ccnt.rest.domain.RankList;
import zju.ccnt.rest.domain.Resource;
import zju.ccnt.rest.domain.ResourceClass;
import zju.ccnt.rest.service.BusinessResourceServiceImpl;
import zju.ccnt.rest.service.util.constant.ResourceActionType;

import java.security.Principal;
import java.util.*;

/**
 * Created by zha on 14/11/11.
 */
@RestController
@RequestMapping(value = "/business_resource")
public class BusinessResourceController {

    private BusinessResourceServiceImpl businessResourceService;
    private FileServerProxy fileServerProxy;

    @Autowired
    public BusinessResourceController(BusinessResourceServiceImpl businessResourceService,
                                      FileServerProxy fileServerProxy){
        this.businessResourceService = businessResourceService;
        this.fileServerProxy = fileServerProxy;
    }

    @RequestMapping(value = "/rank_list/content/{rankId}")
    @PreAuthorize(value = "permitAll")
    public Page<Map<String, Object>> getRankListContentList(@PathVariable String rankId, Authentication authentication,
                                                            @RequestParam(required = false, defaultValue = "0") int page,
                                                            @RequestParam(required = false, defaultValue = "10") int size){
        return businessResourceService.getResourceRankListContent(rankId, authentication, page, size);
    }

    /**
     * 获取资源榜单的详细信息，非数据信息
     * @param rankId
     * @param principal
     * @return
     */
    @RequestMapping(value = "/rank_list/detail/{rankId}")
    @PreAuthorize(value = "hasRole('BUSINESS')")
    public ResponseEntity<ApiReplyRankList> AboutResourceRankList(@PathVariable String rankId, Principal principal){
        HttpStatus status ;
        ApiReplyRankList apiReplyRankList = null;
        RankList rankList = businessResourceService.getResourceRankList(rankId, principal.getName());
        if (rankList == null) status = HttpStatus.NOT_FOUND;
        else{
            status = HttpStatus.OK;
            apiReplyRankList = new ApiReplyRankList(rankList);
        }
        return new ResponseEntity<ApiReplyRankList>(apiReplyRankList, status);
    }

    /**
     *  新增资源列表
     * @param apiCreateRankList
     * @param principal
     * @return
     */
    @RequestMapping(value = "/rank_list", method = RequestMethod.POST)
    @PreAuthorize(value = "hasRole('BUSINESS')")
    @ResponseBody
    public ApiReplyRankList addResourceRankList(@RequestBody ApiCreateRankList apiCreateRankList, Principal principal){
        return new ApiReplyRankList(businessResourceService.addResourceRankList(apiCreateRankList, principal.getName()));
    }

    /**
     * 创建新的资源分类
     * @param apiCreateResourceClass
     * @param principal
     * @return
     */
    @RequestMapping(value = "/class", method = RequestMethod.POST)
    @PreAuthorize(value = "hasRole('BUSINESS')")
    @ResponseBody
    public ApiReplyCreateBusinessClass addResourceClass(@RequestBody ApiCreateResourceClass apiCreateResourceClass, Principal principal){
        return businessResourceService.addResourceClass(apiCreateResourceClass, principal.getName());
    }

    /**
     *  修改制定资源分类的分类名
     * @param newName
     * @param classId
     * @param principal
     * @return
     */
    @RequestMapping(value = "/class/{classId}")
    @PreAuthorize(value = "hasRole('BUSINESS')")
    @ResponseBody
    public ResourceClass editResourceClass(@RequestBody String newName, @PathVariable String classId, Principal principal){
        return businessResourceService.updateResourceClass(newName, classId, principal.getName());
    }


    /**
     * 删除制定ID的商家资源
     * @param id
     * @param principal
     * @return
     */
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    @PreAuthorize(value="hasRole('BUSINESS')")
    public ResponseEntity<ApiReplyBusinessResource> deleteBusinessResource(@PathVariable String id, Principal principal){
        BusinessResource resource = businessResourceService.removeBusinessResource(id, principal.getName());
        return new ResponseEntity<ApiReplyBusinessResource>(
                new ApiReplyBusinessResource(resource),
                HttpStatus.OK
        );
    }

    /**
     * 查询指定ID的商家资源
     * @param id
     * @return
     */
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public ResponseEntity<ApiReplyBusinessResource> getBusinessResourceById(@PathVariable String id){
        BusinessResource businessResource = businessResourceService.getSingleBusinessResource(id);

        HttpStatus status;
        ApiReplyBusinessResource replyResource = null;
        if (businessResource == null) status = HttpStatus.NOT_FOUND;
        else {
            status = HttpStatus.OK;
            replyResource = new ApiReplyBusinessResource(businessResource);
        }
        return new ResponseEntity(replyResource, status);
    }


    /**
     * 只允许商家用户查询自家的按分类资源列表
     * 终端用户只能按照开放的资源榜单查询资源信息
     * @return
     */
    @RequestMapping(value = "/{businessId}/{classId}", method = RequestMethod.GET)
    @PreAuthorize(value="hasRole('BUSINESS')")
    public Page<ApiReplyBusinessResource> getBusinessResource(@PathVariable String businessId, @PathVariable String classId, Principal principal,
                                                                        @RequestParam(required = false) String [] sort,
                                                                        @RequestParam(required = false, defaultValue = "0") int page,
                                                                        @RequestParam(required = false, defaultValue = "10") int size){
        Page<BusinessResource> businessResources = businessResourceService.getBusinessResource(principal.getName(),
                                                        businessId, classId, page, size, sort);
        Iterator<BusinessResource> iterator = businessResources.iterator();
        List<ApiReplyBusinessResource> replyResources = new ArrayList<ApiReplyBusinessResource>();
        while (iterator.hasNext()){
            replyResources.add(new ApiReplyBusinessResource(iterator.next()));
        }
        return new PageImpl<ApiReplyBusinessResource>(replyResources);
    }

    /**
     * 获取商家资源的下载链接
     * @param resourceId
     * @return
     *       从文件服务器下载该资源的地址
     */
    @PreAuthorize(value = "hasRole('USER')")
    @RequestMapping(method = RequestMethod.GET)
    public ResponseEntity<String> downloadResource(@PathVariable String resourceId){
        BusinessResource resource = businessResourceService.getSingleBusinessResource(resourceId);
        HttpStatus status = null;
        String callback = null;
        if (resource == null){
            status = HttpStatus.NOT_FOUND;
        }else {
            status = HttpStatus.OK;
            callback = resource.getResource().getAddress();
        }
        return new ResponseEntity<String>(callback, status);
    }


    /**
     * 终端用户上传商家资源请求
     * @param apiResource
     * @return
     */
    @RequestMapping(method = RequestMethod.POST)
    @PreAuthorize(value = "hasAnyRole('BUSINESS', 'USER')")
    public ResponseEntity<Object> uploadResource(@RequestBody ApiCreateResource apiResource){
        HttpStatus status = null;
        Object replyResource = null;
        ApiCreateBusinessResource apiBusinessResource = apiResource.getBusinessResource();
        Resource resource = businessResourceService.getResource(apiBusinessResource.getHashValue());
        if (resource == null){
            //资源服务器中没有该资源信息，则需先提交上传请求
            //选择合适的服务器，返回其接受上传请求的地址
            replyResource = fileServerProxy.selectFileServer(apiResource.getResource().getSize());
            if (replyResource == null){
                status = HttpStatus.NOT_ACCEPTABLE;
            } else {
                status = HttpStatus.USE_PROXY;
                fileServerProxy.addWaitingForPostUpload(apiBusinessResource.getHashValue(), apiBusinessResource.getBusinessId(), apiResource, apiBusinessResource.getUploaderId());
            }
            status = replyResource == null ? HttpStatus.NOT_ACCEPTABLE : HttpStatus.USE_PROXY;
        } else if (resource.isHasUploaded()){
            //资源服务器中已经存在完整的该资源信息，直接添加对应的商家资源信息
            BusinessResource businessResource = businessResourceService.getBusinessResource(apiBusinessResource.getBusinessId(), apiBusinessResource.getHashValue());
            status = businessResource == null ? HttpStatus.OK : HttpStatus.CONFLICT;
            if (businessResource == null) businessResource = businessResourceService.createBusinessResource(apiBusinessResource);
            replyResource = new ApiReplyBusinessResource(businessResource);
        }else {
            //资源服务器中该资源处于等待上传的状态，返回redis中正在使用的该资源上传地址,让该用户也上传该文件
            replyResource = fileServerProxy.getFileUploadUrl(apiBusinessResource.getHashValue());
            status = HttpStatus.SEE_OTHER;
            businessResourceService.createBusinessResource(apiBusinessResource);
            fileServerProxy.addWaitingForUploaded(apiBusinessResource.getHashValue(), apiBusinessResource.getBusinessId(), apiBusinessResource.getUploaderId());
        }

        return new ResponseEntity<Object>(replyResource, status);
    }

    /**
     * 文件服务器发起，表示某物理资源文件刚处于接受上传的状态中
     * @return
     */
    @RequestMapping(value = "/resource/uploading/{hashValue}", method = RequestMethod.POST)
    @ResponseBody
    @Transactional
    public void postResourceUploadMsg(@PathVariable String hashValue){
        Set<String> businessIds = fileServerProxy.getAttempBusiness(hashValue);
        for (String businessId : businessIds){
            ApiCreateResource apiCreateResource = fileServerProxy.removeUploadInitial(hashValue, businessId);
            String address = fileServerProxy.getFileUploadUrl(hashValue);
            apiCreateResource.getResource().setAddress(address);
            //首次尝试上传过后，resource中判定存在该资源
            businessResourceService.addResource(apiCreateResource.getResource());
            //business_resource中创建该资源
            businessResourceService.createBusinessResource(apiCreateResource.getBusinessResource());
        }
    }

    /**
     * 物理资源上传完成
     * @param
     * @return
     */
    @RequestMapping(value = "/resource/uploaded/{hashValue}",method = RequestMethod.POST)
    @ResponseBody
    public void uploadedResource(@PathVariable String hashValue){
        businessResourceService.uploadedResource(hashValue);
        Set<String> uploaders = fileServerProxy.getSuccessUploaders(hashValue);
        //所有在试图上传该资源的目标商家
        Set<String> businessIds = fileServerProxy.getAttempBusiness(hashValue);
        for (String business: businessIds) {
            Set<String> attempUploaders = fileServerProxy.getAttempUploaders(hashValue, business);
            attempUploaders.retainAll(uploaders);
            businessResourceService.addResourceAction(hashValue, business, attempUploaders, ResourceActionType.UPLOAD);
        }

        fileServerProxy.actionOnUploaded(hashValue);
    }

}
